/*!
 * @file inifile.hh
 * @brief Obiekt reprezentujący plik ini
 */

#ifndef __ENGINE_BASIC_INIFILE_HH
#define __ENGINE_BASIC_INIFILE_HH

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <list>

#include "engine/pawirr.hh"

class inifileItem {
public:
	/*!
	 * @brief Tworzy obiekt do przechowywania konkretnej informacji
	 * @param name Nazwa zmiennej
	 * @param value Wartość
	 * @return Obiekt
	 */
	inifileItem(std::string name, std::string value);

	/*!
	 * @brief Zwraca wartość zrzutowaną na int
	 * @return Wartość
	 */
	int getInt() const;

	/*!
	 * @brief Zwraca wartość zrzutowaną na float
	 * @return Wartość
	 */
	float getFloat() const;

	/*!
	 * @brief Zwraca wartość zrzutowaną na string
	 * @return Wartość
	 */
	std::string getString() const;

	/*!
	 * @brief Pobieranie nazwy zmiennej
	 * @return Nazwa zmiennej
	 */
	std::string getName() const;

private:
	/*!
	 * @brief Nazwa zmiennej
	 */
	const std::string name;

	/*!
	 * @brief Wartość zmiennej
	 */
	const std::string value;
};

/*!
 * @brief Sekcja z pliku ini
 */
class inifileSection {
public:
	/*!
	 * @brief Tworzy sekcję
	 * @param name Nazwa sekcji
	 * @return Obiekt
	 */
	inifileSection(std::string name);

	/*!
	 * @brief Dodawanie zmiennej do sekcji
	 * @param name Nazwa
	 * @param value Wartość
	 */
	void addItem(std::string name, std::string value);

	/*!
	 * @brief Pobieranie nazwy sekcji
	 * @return Nazwa sekcji
	 */
	std::string getName() const;

	/*!
	 * @brief Pobieranie itemu
	 * @param name Żądana nazwa zmiennej
	 * @return Wskaźnik na item
	 */
	inifileItem *getItem(std::string name) const;

private:
	/*!
	 * @brief Nazwa sekcji
	 */
	const std::string name;

	/*!
	 * @brief Lista itemów
	 */
	std::list<inifileItem*> sectionitem_stack;
};

/*!
 * @brief Pliki ini
 */
class inifile {
public:
	/*!
	 * @brief Konstruktor. Wczytuje plik ini
	 * @param path Ścieżka do pliku
	 * @return Obiekt
	 */
	inifile(std::string path);

	/*!
	 * @brief Pobieranie wartości zrzutowanej na int
	 * @param section Nazwa sekcji
	 * @param name Nazwa zminnej
	 * @param defaultVal Wartość zwracana jeśli sekcja/zmienna nie istnieje
	 * @return Wartość z pliku lub domyślna
	 */
	int getInteger(std::string section, std::string name, int defaultVal) const;

	/*!
	 * @brief Pobieranie wartości zrzutowanej na float
	 * @param section Nazwa sekcji
	 * @param name Nazwa zminnej
	 * @param defaultVal Wartość zwracana jeśli sekcja/zmienna nie istnieje
	 * @return Wartość z pliku lub domyślna
	 */
	float getFloat(std::string section, std::string name, float defaultVal) const;

	/*!
	 * @brief Pobieranie wartości zrzutowanej na string
	 * @param section Nazwa sekcji
	 * @param name Nazwa zminnej
	 * @param defaultVal Wartość zwracana jeśli sekcja/zmienna nie istnieje
	 * @return Wartość z pliku lub domyślna
	 */
	std::string getString(std::string section, std::string name, std::string defaultVal) const;

private:
	/*!
	 * @brief Pobieranie wskaźnika na item
	 * @param section Nazwa sekcji
	 * @param name Nazwa zmiennej
	 * @return Wskaźnik na item lub NULL gdy błąd
	 */
	inifileItem *getItem(std::string section, std::string name) const;

	/*!
	 * @brief Pobieranie sekcji
	 * @param section Nazwa sekcji
	 * @return Wskaźnik na sekcję lub na NULL gdy sekcja nie istnieje
	 */
	inifileSection *getSection(std::string section) const;

	/*!
	 * @brief Właściwe przetwarzanie pliku
	 */
	void load();

	/*!
	 * @brief Czy poprawnie wczytano plik?
	 */
	bool isFileLoaded;

	/*!
	 * @brief Adres wczytanego pliku
	 */
	const std::string path;

	/*!
	 * @brief Lista sekcji
	 */
	std::list<inifileSection *> inisections_stack;
};

#else
class inifile;
#endif
